const request = require('request-promise')
const config = require('config')
const nextcloud = config.get('nextcloud')
const VCard = require('vcards-js')
const dav = require('dav')
const vCard = require('vcf')
import {ncOptions,getBase64Auth} from '../common'

const user_provison_path = '/ocs/v2.php/cloud/users',
    password_policy_path = '/ocs/v2.php/apps/password_policy/api/v1/validate',
    group_provision_path = '/ocs/v2.php/cloud/groups'


const account2Card = (user)=>{
    let card = VCard();
    card.cellPhone = user.phone
    card.email = user.email
    card.organization = user.organization
    card.title = user.title
    card.nickname = user.displayname
    return card
}

const card2Account = (card)=>{
    let user = {}
    user.phone = card.tel?._data
    user.title = card.title?._data
    user.email = card.email?._data
    user.organization = card.org?._data
    user.displayname = card.nickname?._data
    return user
}

export const addOrUpdateContact = async (user)=>{
    let card , xhr, contact, vcards, vcard, addressBook,
        homeUrl = `${nextcloud.host}/remote.php/dav/addressbooks/users/${user.id}`,
        principalUrl = `${nextcloud.host}/remote.php/dav/principals/users/${user.id}`,
        rootUrl = `${homeUrl}/contacts`
    let account = {
        rootUrl,
        principalUrl,
        homeUrl,
        credentials: {
            username: user.id,
            password: user.passwd
        }
    }
    xhr = new dav.transport.Basic(
        new dav.Credentials({
            username: user.id,
            password: user.passwd
        })
    )
    addressBook = await dav.listAddressBooks(account,{
        xhr:xhr,
        server: rootUrl,
        accountType: 'carddav'
    })
    if(!addressBook||!addressBook.length){
        await dav.createAccount({
            server: rootUrl,
            xhr: xhr,
            accountType: 'carddav'
        })
        addressBook = await dav.listAddressBooks(account,{
            xhr:xhr,
            server: rootUrl,
            accountType: 'carddav'
        })
    }
    vcards = await dav.listVCards(addressBook[0], {
        xhr: xhr
    });
    if(vcards&&vcards.length){
        vcard = new vCard().parse(vcards[0].addressData)
        contact = card2Account(vcard.data)
        user = {...contact,...user}
    }
    card = account2Card(user)
    await dav.createCard(addressBook[0], {
        filename: `${user.id}.vcf`,
        data: card.getFormattedString(),
        xhr: xhr
    });
}

const getContact = async (user)=>{
    let homeUrl = `${nextcloud.host}/remote.php/dav/addressbooks/users/${user.id}`,
        principalUrl = `${nextcloud.host}/remote.php/dav/principals/users/${user.id}`,
        serverUrl = `${homeUrl}/contacts`,xhr,addressBook,contact,vcards,vcard
    let account = {
        rootUrl:serverUrl,
        principalUrl,
        homeUrl,
        credentials:{
            username:user.id,
            password:user.passwd
        }
    }
    xhr = new dav.transport.Basic(
        new dav.Credentials({
            username: user.id,
            password: user.passwd
        })
    )
    addressBook = await dav.listAddressBooks(account,{
        xhr:xhr,
        server: serverUrl,
        accountType: 'carddav'
    })
    if(addressBook&&addressBook.length){
        vcards = await dav.listVCards(addressBook[0], {
            xhr: xhr
        });
        if(vcards&&vcards.length){
            vcard = new vCard().parse((vcards[0].addressData))
            contact = card2Account(vcard.data)
        }
    }
    return contact
}

export const findUsers = async () => {
    let options = {...ncOptions},result
    options.uri = nextcloud.host + user_provison_path
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.method = 'GET'
    result = await request(options)
    result = result.ocs&&result.ocs.data&&result.ocs.data.users
    return result
}

export const addUserGroup = async (group)=>{
    let options = {...ncOptions},result
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.uri = `${nextcloud.host}${group_provision_path}`
    options.form = {
        groupid: group
    }
    result = await request(options)
    result = result.ocs && result.ocs.data
    return result
}


export const registerUser = async (user) => {
    let options = {...ncOptions}, result, error,nc_user,xhr,account
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.uri = nextcloud.host + password_policy_path
    options.form = {password: user.passwd}
    result = await request(options)
    if (result && result.ocs && result.ocs.data && result.ocs.data.passed === false) {
        error = new Error();
        error.status = 401;
        error.message = result.ocs.data.reason
        throw error
    }
    options.uri = nextcloud.host + user_provison_path
    nc_user = {userid: user.phone, password: user.passwd, displayName: user.displayname||user.phone, groups: [nextcloud.group],settings:user.settings}
    options.form = nc_user
    await request(options)
    user.id = user.id ||user.phone
}

export const setUserAttribute = async (userid, key, value) => {
    let options = {...ncOptions}
    options.uri = nextcloud.host + user_provison_path + '/' + userid
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.method = 'PUT'
    options.form = {key: key, value: value}
    await request(options)
}

export const resetUserPasswd = async (userid, newPasswd) => {
    await setUserAttribute(userid,"password",newPasswd)
}

export const deleteUser = async (userid)=>{
    let options = {...ncOptions}
    options.method = 'DELETE'
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.uri = nextcloud.host + user_provison_path + '/' + userid
    await request(options)
}

export const findUser = async (userid)=>{
    let options = {...ncOptions},result
    options.uri = nextcloud.host + user_provison_path + "/" + userid
    options.headers.Authorization = getBase64Auth(nextcloud.user, nextcloud.password)
    options.method = 'GET'
    result = await request(options)
    result = result.ocs&&result.ocs.data&&result.ocs.data
    return result
}

export const editUser = async (user)=>{
    await addOrUpdateContact(user)
    if("settings" in user) {
        await setUserAttribute(user.id,"settings",user.settings)
    }
}

export const getUser = async (user)=>{
    let self = await findUser(user.id)
    self = ['id', 'email','displayname','settings'].reduce((result, key) => { result[key] = self[key]; return result; }, {});
    let contact = await getContact(user)
    return {...self,...contact}
}

